package org.tamal.classinfo;

import java.io.DataInputStream;
import java.io.IOException;

/**
 * The Annotation data structure is a kind of attribute data structure. It is
 * used to fetch:
 * <ul>
 * <li> {@link Attribute#VISIBLE_ANNOTATION}</li>
 * <li> {@link Attribute#INVISIBLE_ANNOTATION}</li>
 * <li> {@link Attribute#VISIBLE_PARAMETER_ANNOTATION}</li>
 * <li> {@link Attribute#INVISIBLE_PARAMETER_ANNOTATION}</li>
 * </ul>
 * Even an {@link ElementValue} can contain an annotation.
 *
 * @author Tamal Kanti Nath
 */
public final class Annotation {
    private final ClassInfo cls;
    private int typeIndex;
    private ElementValuePair[] pairs;

    /**
     * Constructs Annotation Structure from DataInputStream.
     * @param in the DataInputStream
     * @param cls The ClassInfo reference
     * @throws IOException exception
     * @see #readAnnotations(DataInputStream, ClassInfo)
     * @see ElementValue#ElementValue(DataInputStream, ClassInfo)
     */
    Annotation(DataInputStream in, ClassInfo cls) throws IOException {
        this.cls = cls;
        typeIndex = in.readUnsignedShort();
        pairs = new ElementValuePair[in.readUnsignedShort()];
        for (int i = 0; i < pairs.length; ++i) {
            pairs[i] = new ElementValuePair(in, cls);
        }
    }

    /**
     * Returns type index.
     * @return the type index
     */
    public int getTypeIndex() {
        return typeIndex;
    }

    /**
     * Returns type.
     * @return the type
     */
    public String getType() {
        return cls.getPool()[typeIndex].toString();
    }

    /**
     * Returns pairs.
     * @return the pairs
     */
    public ElementValuePair[] getPairs() {
        return pairs;
    }

    @Override
    public String toString() {
        return getType();
    }

    /**
     * Reads Annotations from DataInputStream.
     * @param in the DataInputStream
     * @param cls The ClassInfo reference
     * @return the array of InnerClass
     * @throws IOException exception
     * @see #readParameterAnnotations(DataInputStream, ClassInfo)
     * @see Attribute
     */
    static Annotation[] readAnnotations(DataInputStream in, ClassInfo cls)
        throws IOException {
        Annotation[] table = new Annotation[in.readUnsignedShort()];
        for (int i = 0; i < table.length; ++i) {
            table[i] = new Annotation(in, cls);
        }
        return table;
    }

    /**
     * Reads Parameter Annotations from DataInputStream.
     * @param in the DataInputStream
     * @param cls The ClassInfo reference
     * @return the array of InnerClass
     * @throws IOException exception
     * @see Attribute
     */
    static Annotation[][] readParameterAnnotations(DataInputStream in,
        ClassInfo cls) throws IOException {
        Annotation[][] t = new Annotation[in.readUnsignedByte()][];
        for (int i = 0; i < t.length; ++i) {
            t[i] = readAnnotations(in, cls);
        }
        return t;
    }
}
